﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using Services;
using SpaceBattle.Logic.SampleLevel;
using System.IO.IsolatedStorage;
using System.IO;
using Utilities;

namespace SpaceBattle.Menu
{
  public class LeaderboardEntry
  {
    public int Score { get; set; }
    public string Name { get; set; }
    public string Date { get; set; }
  }

  public class StateEntry
  {
      public ArrayList<GameShipConfig> Ships { get; set; }
      public CampaignState CampaignState { get; set; }

      public StateEntry() { }

      public StateEntry(ArrayList<GameShipConfig> ships, CampaignState state)
      {
          Ships = ships;
          CampaignState = state;
      }
  }

  public class GameShipConfig
  {
      public int Index { get; set; }
      public int Unlocked { get; set; }
      public int Price { get; set; }
      public ArrayList<WeaponAsset> Weapons { get; set; }
      public int ArLevel { get; set; }
      public int ShLevel { get; set; }
      public int EnLevel { get; set; }
      public int FTLevel { get; set; }
      public int ChLevel { get; set; }

      public GameShipConfig(int index, int unlocked, int price, int ar_level, int sh_level, int en_level, int ft_level, int ch_level, ArrayList<WeaponAsset> weapons)
      {
          Index = index;
          Unlocked = unlocked;
          Price = price;
          Weapons = weapons;
          ArLevel = ar_level;
          ShLevel = sh_level;
          EnLevel = en_level;
          FTLevel = ft_level;
          ChLevel = ch_level;
      }
  }

  public class WeaponAsset
  {
      public static int Number = 11;
      public static int FieldNumber = 3;

      public WeaponType Type;
      public int Unlocked;
      public int UpgradeLv;
  }

  public class CampaignState
  {
      public int Score { get; set; }
      public int Credits { get; set; }
      public int Lives { get; set; }
      public int LevelPlayed { get; set; }
      public ArrayList<GameShipConfig> Ships { get; set; }

      public CampaignState(int score, int credits, int lives, int level_played, ArrayList<GameShipConfig> ships)
      {
          Score = score;
          Credits = credits;
          Lives = lives;
          LevelPlayed = level_played;
          Ships = ships;
      }
  }

  public static class Leaderboard
  {

    private static Func<StreamReader, ArrayList<LeaderboardEntry>> read_entries = reader =>
    {
      ArrayList<LeaderboardEntry> tempScores = new ArrayList<LeaderboardEntry>();
      var strings = reader.ReadToEnd().Split(new[] { '\n' });

      for (int i = 0; i < strings.Length; i++)
      {
          var s = strings[i];
          var splits = s.Split(new[] { ',', '\n' });
          if (splits.Length >= 2)          
              tempScores.Add(new LeaderboardEntry() { Name = splits[0], Score = int.Parse(splits[1]), Date = splits[2] });
      }

      return tempScores;
    };

    private static Func<StreamReader, StateEntry> read_campaign_state = reader =>
    {
        var s = reader.ReadToEnd().Split(new[] { ',' });
        int n_ships = 6;

        ArrayList<GameShipConfig> csc = new ArrayList<GameShipConfig>(), c_ships = new ArrayList<GameShipConfig>();

        var lenght = 8 * n_ships + WeaponAsset.FieldNumber * n_ships * WeaponAsset.Number;
        var offset = 8 + WeaponAsset.FieldNumber * WeaponAsset.Number;

        var i = 0;

        for (i = 4; i < lenght; i += offset)
        {
            var weapons = new ArrayList<WeaponAsset>();

            for (int j = 0; j < WeaponAsset.Number; j++)
            {
                var index = i + 8 + WeaponAsset.FieldNumber * j;

                weapons.Add(new WeaponAsset { Type = (WeaponType)int.Parse(s[index]), Unlocked = int.Parse(s[index+1]), UpgradeLv = int.Parse(s[index+2]) });
            }

            c_ships.Add(new GameShipConfig(int.Parse(s[i]), int.Parse(s[i+1]), int.Parse(s[i + 2]), int.Parse(s[i+3]), 
                int.Parse(s[i+4]), int.Parse(s[i+5]), int.Parse(s[i+6]), int.Parse(s[i+7]), weapons));
        }        

        for (i = lenght + 4; i < lenght * 2; i+= offset)
        {
            var weapons = new ArrayList<WeaponAsset>();

            for (int j = 0; j < WeaponAsset.Number; j++)
            {
                var index = i + 8 + WeaponAsset.FieldNumber * j;

                weapons.Add(new WeaponAsset { Type = (WeaponType)int.Parse(s[index]), Unlocked = int.Parse(s[index + 1]), UpgradeLv = int.Parse(s[index + 2]) });
            }

            csc.Add(new GameShipConfig(int.Parse(s[i]), int.Parse(s[i + 1]), int.Parse(s[i + 2]), int.Parse(s[i + 3]),
                int.Parse(s[i + 4]), int.Parse(s[i + 5]), int.Parse(s[i + 6]), int.Parse(s[i + 7]), weapons));
        }

        return new StateEntry(csc, new CampaignState(int.Parse(s[0]), int.Parse(s[1]), int.Parse(s[2]), int.Parse(s[3]), c_ships));
    };

    private static Action<StreamWriter, List<LeaderboardEntry>> write_entries = (writer, entries) =>
        writer.Write(entries.Aggregate("", (ss, s) => s.Name + "," + s.Score + "," + s.Date + "\n" + ss));

    private static Action<StreamWriter, StateEntry> write_camp_state = (writer, entry) =>
        {
            var s = entry.CampaignState.Score + "," + entry.CampaignState.Credits + "," + entry.CampaignState.Lives + "," + entry.CampaignState.LevelPlayed;

            for (int i = 0; i < entry.CampaignState.Ships.Count; i++)
            {
                var ship = entry.CampaignState.Ships[i];
                s += "," + ship.Index + "," + ship.Unlocked + "," + ship.Price + "," + ship.ArLevel + "," + ship.ShLevel + "," + 
                    ship.EnLevel + "," + ship.FTLevel + "," + ship.ChLevel;

                for (int j = 0; j < ship.Weapons.Count; j++)
                {
                    var w = ship.Weapons[j];

                    s += "," + (int)w.Type + "," + w.Unlocked + "," + w.UpgradeLv;
                }
            }

            for (int i = 0; i < entry.Ships.Count; i++)
            {
                var ship = entry.Ships[i];
                s += "," + ship.Index + "," + ship.Unlocked + "," + ship.Price + "," + ship.ArLevel + "," + ship.ShLevel + "," + 
                    ship.EnLevel + "," + ship.FTLevel + "," + ship.ChLevel;

                for (int j = 0; j < ship.Weapons.Count; j++)
                {
                    var w = ship.Weapons[j];

                    s += "," + (int)w.Type + "," + w.Unlocked + "," + w.UpgradeLv;
                }
            }

            writer.Write(s);
        };
      //writer.Write(entry.CampaignState.Score + "," + entry.CampaignState.Credits + "," + entry.CampaignState.Lives + ',' + entry.CampaignState.LevelPlayed +
      //entry.CampaignState.Ships.Aggregate("", (ss, s) => "," + s.Index + "," + s.Unlocked + "," + s.Price + "," + s.ArLevel + "," + s.ShLevel + "," + s.EnLevel + "," +
      //    s.FTLevel + s.Weapons.Aggregate("", (ws, w) => "," + (int)w.Type + "," + w.Unlocked + "," + w.UpgradeLv + ws) + ss) +
      //entry.Ships.Aggregate("", (ss, s) => "," + s.Index + "," + s.Unlocked + "," + s.Price + "," + s.ArLevel + "," + s.ShLevel + "," + s.EnLevel + "," +
      //    s.FTLevel + s.Weapons.Aggregate("", (ws, w) => "," + (int)w.Type + "," + w.Unlocked + "," + w.UpgradeLv + ws) + ss));


    public static void SaveCampaignState(StateEntry entry)
    {
#if WINDOWS || XBOX
        using (var writer = new StreamWriter("campaign.txt"))
            write_camp_state(writer, entry);
#else
      using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
      {
        appStorage.DeleteFile("campaign.txt");
        using (var streamFile = appStorage.OpenFile("campaign.txt", FileMode.OpenOrCreate))
        using (var writer = new StreamWriter(streamFile))
          write_camp_state(writer, entry);
      }
#endif
    }

    public static void AddScore(LeaderboardEntry current_score)
    {
      var new_scores = new[] { current_score }.ToList();
      var old_score = Leaderboard.GetScores();
      for (int i = 0; i < old_score.Count; i++)
          new_scores.Add(old_score[i]);
      new_scores = new_scores.OrderByDescending(s => s.Score).ToList();
      if (new_scores.Count > 7)
        new_scores = new_scores.Take(7).ToList();
#if WINDOWS || XBOX
      using (var writer = new StreamWriter("scores.txt"))
        write_entries(writer, new_scores);
#else
      using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
      {
        appStorage.DeleteFile("scores.txt");
        using (var streamFile = appStorage.OpenFile("scores.txt", FileMode.OpenOrCreate))
        using (var writer = new StreamWriter(streamFile))
          write_entries(writer, new_scores);
      }
#endif
    }

    public static StateEntry ResetCampaignState(bool not_existing)
    {
        ArrayList<GameShipConfig> ships_list = new ArrayList<GameShipConfig>(), campaign_ships = new ArrayList<GameShipConfig>();

        StateEntry cle = new StateEntry();


        if (!not_existing)
        {
            cle = Leaderboard.GetCampaignState();
            ships_list = cle.Ships;
        }
        else
        {
            var base_ships = ConfigurationService.GetBaseConfiguration();

            for (int i = 0; i < 6; i++)
            {
                var ws = new ArrayList<WeaponAsset>();

                for (int j = 0; j < WeaponAsset.Number; j++)
                {
                    var f = 0;
                    for (int k = 0; k < base_ships.Ships[i].PrimaryWeapons.Count; k++)
                        if (base_ships.Ships[i].PrimaryWeapons[k].Type == (WeaponType)j)
                        {
                            f = 1;
                            break;
                        }

                    if (f == 0)
                        for (int k = 0; k < base_ships.Ships[i].SecondaryWeapons.Count; k++)
                            if (base_ships.Ships[i].SecondaryWeapons[k].Type == (WeaponType)j)
                            {
                                f = 1;
                                break;
                            }
                    ws.Add(new WeaponAsset() { Type = (WeaponType)j, Unlocked = f, UpgradeLv = -1 + f });
                }

                ships_list.Add(new GameShipConfig(i, i == 0 ? 1 : 0, i * 100 + 200, 0, 0, 0, 0, 0, ws));
            }
            //ships_list = campaign_ships;
        }

        var r = new StateEntry(ships_list, new CampaignState(0,0,3,0,ships_list));

        SaveCampaignState(r);

        return r;
    }

    public static StateEntry GetCampaignState()
    {
#if WINDOWS || XBOX
        try
        {
        using (var reader = new StreamReader("campaign.txt"))
          return read_campaign_state(reader);
      }
      catch (Exception) 
        { return ResetCampaignState(true); }
#else
      using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
      {
        using (var streamFile = appStorage.OpenFile("campaign.txt", FileMode.OpenOrCreate))
        {
          try
          {
            using (var reader = new StreamReader(streamFile))
              return read_campaign_state(reader);
          }
          catch (Exception) { return ResetCampaignState(true); }
        }
      }
#endif
    }

    public static ArrayList<LeaderboardEntry> GetScores()
    {
#if WINDOWS || XBOX
      try
      {
        using (var reader = new StreamReader("scores.txt"))
          return read_entries(reader);
      }
      catch (Exception) { return new ArrayList<LeaderboardEntry>(); }
#else
      using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
      {
        using (var streamFile = appStorage.OpenFile("scores.txt", FileMode.OpenOrCreate))
        {
          try
          {
            using (var reader = new StreamReader(streamFile))
              return read_entries(reader);
          }
          catch (Exception) { return new ArrayList<LeaderboardEntry>(); }
        }
      }
#endif
    }
  }
}
